#include "common_impl.h"


/* variables globales */
#define BACKLOG 1024
#define MAXHOSTNAME 256
static int DSM_MODE_NUM=100;


/* un tableau gerant les infos d'identification */
/* des processus dsm */
dsm_proc_t *proc_array = NULL; 

/* le nombre de processus effectivement crees */
volatile int num_procs_creat = 0;

void usage(void)
{
	fprintf(stdout,"Usage : dsmexec machine_file executable arg1 arg2 ...\n");
	fflush(stdout);
	exit(EXIT_FAILURE);
}

void sigchld_handler(int sig)
{
	/* on traite les fils qui se terminent */
	/* pour eviter les zombies */

}





int main(int argc, char *argv[])
{
	if (argc < 3){
		usage();
	} else {

		int i;

		int ouverture_fichier;
		size_t lecture_fichier;
		char noms_machines[256];
		int nombre_processus=0;
		int indice_char=0;
		int taille_max_machine=0;
		int taille_machine;
		int sock_ecoute; //Socket d'�coute
		int listn;
		int bnd;
		int port=33000;
		int maxbuflen=1024;
		int pipe_err;
		int pipe_out;
		struct sockaddr_in addr;
		char cwd[1024];
		if (getcwd(cwd, sizeof(cwd)) == NULL)
			perror("getcwd() error");
		else
			printf("current working directory is: %s\n", cwd);
		char *chemin=strdup(cwd);
		char * new_chemin=strdup(strcat(chemin,"/bin/dsmwrap"));

		printf("current working directory is: %s\n", new_chemin);
		pid_t fils[nombre_processus];
		int *fds_out=NULL;
		fds_out=malloc(sizeof(int)*nombre_processus);
		int *fds_err=NULL;
		fds_err=malloc(sizeof(int)*nombre_processus);
		struct pollfd *pollfds=NULL;
		pollfds=malloc(sizeof(struct pollfd)*2*nombre_processus);

		int sock_serv[nombre_processus];
		struct sockaddr_in distaddr[nombre_processus];

		int ports[nombre_processus];
		int readnames[nombre_processus];
		char*buffer_int=malloc(sizeof(char)*100);
		char** machines=NULL;
		int j=0;
		int k;
		char* tmp=NULL;
		int rt=0;
		int buflen=0;
		int raz=0;
		int boucle=0;
		int mod_y;
		int poll_use;
		int z;
		int boucle_len=0;
		char*buffer_poll=malloc(sizeof(char)*maxbuflen);

		/* Mise en place d'un traitant pour recuperer les fils zombies*/
		/* XXX.sa_handler = sigchld_handler; */

		/* lecture du fichier de machines */


		ouverture_fichier=open("machine_file",O_RDONLY);

		lecture_fichier=read(ouverture_fichier,&noms_machines,DSM_MODE_NUM*20);

		close(ouverture_fichier);
		//printf("noms des machines: %s \n", noms_machines);

		/* 1- on recupere le nombre de processus a lancer */
		while (noms_machines[indice_char] != '\0'){
			if (noms_machines[indice_char] =='\n'){
				nombre_processus++;
			}
			indice_char++;
		}
		printf("Nombre de processus a lancer: %d \n",nombre_processus);

		/* 2- on recupere les noms des machines : le nom de */
		/* la machine est un des elements d'identification */

		machines=malloc(sizeof(char*)*nombre_processus*256);



		indice_char=0;

		while (noms_machines[indice_char] != '\0'){
			taille_machine=0;
			while (noms_machines[indice_char] !='\n'){
				taille_machine++;
				indice_char++;
			}
			if (taille_machine>taille_max_machine){
				taille_max_machine=taille_machine;
			}
			indice_char++;
		}

		printf("Taille max machine: %d\n",taille_max_machine);


		tmp=malloc(sizeof(char)*taille_max_machine);
		j=0;
		for (i=0;i<nombre_processus;i++){
			k=0;
			while(noms_machines[j] != '\n'){
				tmp[k]=noms_machines[j];
				j++;
				k++;
			}
			j++;
			machines[i]=strdup(tmp);
		}
		for (i=0;i<nombre_processus;i++){
			printf("Nom de la machine %d: %s \n",i,machines[i]);
		}
		/* creation de la socket d'ecoute */

		sock_ecoute=socket(AF_INET, SOCK_STREAM, 0);
		if ( sock_ecoute == -1 ) {
			perror( "socket" ); exit( EXIT_FAILURE );
		}

		/* + ecoute effective */


		/* Mise a zero de tous les bits de la structure d'adresse de la socket
	     et remplissage de certains champs de la structure
	     - structure statique non initialisee par le compilateur*/

		memset(&addr, 0,sizeof (addr));
		addr.sin_family = AF_INET;
		addr.sin_port = htons(port);
		addr.sin_addr.s_addr = htonl(INADDR_ANY);


		bnd=bind(sock_ecoute, (const struct sockaddr*)&addr, sizeof(addr));
		if ( bnd == -1 ) {
			perror( "bind" ); exit( EXIT_FAILURE );
		}

		listn=listen(sock_ecoute,1);
		if ( listn == -1 ) {
			perror( "listen" ); exit( EXIT_FAILURE );
		}



		/* creation des fils */






		for(i = 0; i < nombre_processus ; i++) {

			/* creation du tube pour rediriger stdout */
			int fd_out[2];
			pipe_out=pipe(fd_out);
			if (pipe_out == -1){
				perror( "pipe_out" ); exit( EXIT_FAILURE );
			}

			/* creation du tube pour rediriger stderr */
			int fd_err[2];
			pipe_err=pipe(fd_err);
			if (pipe_err == -1){
				perror( "pipe_err" ); exit( EXIT_FAILURE );
			}

			fils[i] = fork();
			if(fils[i] == -1)
				ERROR_EXIT("fork");

			if (fils[i] == 0) { /* fils */

				num_procs_creat++;
				/* redirection stdout */
				close(fd_out[0]);  //fermeture de l'extremite en lecture
				close(STDOUT_FILENO);
				dup(fd_out[1]);
				close(fd_out[1]);




				/* redirection stderr */
				close(fd_err[0]);
				close(STDERR_FILENO);
				dup(fd_err[1]);
				close(fd_err[1]);



				/* Creation du tableau d'arguments pour le ssh */

				char** newargv=malloc(sizeof(char*)*(argc+2+1));
				newargv[0]=strdup("ssh"); //premier argument
				newargv[1]=strdup(machines[i]); //nom de la machine ou on va executer dsmwrap
				newargv[2]=strdup(new_chemin); //chemin absolu de dsmwrap
				char hostname[MAXHOSTNAME+1];
				gethostname(hostname, MAXHOSTNAME);
				newargv[3]=strdup(hostname); //nom de la machine locale
				int num_port=ntohs(addr.sin_port);
				newargv[4]=malloc(sizeof(char)*256);
				sprintf(newargv[4],"%d",num_port); //numero de port
				ports[i]=num_port;
				for(k=3;k<argc+1;k++){
					newargv[3+k-1]=strdup(argv[k-1]);
				}


				/* jump to new prog : */

				int exec_ssh;
				exec_ssh=execv("/usr/bin/ssh",newargv);
				if (exec_ssh==-1){
					perror( "ssh" ); exit( EXIT_FAILURE );
				}


			}



			else  if(fils[i] > 0) { /* pere */


				fds_out[i]=fd_out[0];
				fds_err[i]=fd_err[0];
				/* fermeture des extremites des tubes non utiles */
				close(fd_out[1]);
				close(fd_err[1]);

			}
		}

		for (k=0;k<nombre_processus;k++){

			pollfds[k].fd=fds_out[k];
			pollfds[k].events=POLLHUP | POLLIN | POLLERR;
			pollfds[k].revents=0;

			pollfds[k+nombre_processus].fd=fds_err[k];
			pollfds[k+nombre_processus].events=POLLHUP | POLLIN | POLLERR;
			pollfds[k+nombre_processus].revents=0;

		}







		printf("Entree dans la boucle du poll: \n");

		//while (boucle == 0){
		for(z=1;z<5;z++){
			do{
				poll_use=poll(pollfds,nombre_processus*2,0);
			}while((poll_use==-1) && (errno==EINTR));
			if(poll_use < 0)
			{
				fprintf(stderr,"Error while polling: %s\n",strerror(errno));
				return -1;
			}
			int y;

			for (y=0;y<2*nombre_processus;y++){
				if (((pollfds[y].revents & POLLIN) == POLLIN) || ((pollfds[y].revents & POLLHUP) == POLLHUP)){
					mod_y=y%nombre_processus;
					rt=0;
					boucle_len=0;
					raz=0;
					do {
						rt=read(pollfds[y].fd,buffer_poll,maxbuflen);
					}while((-1 == rt) && (errno==EINTR));

					if( mod_y == y){
						if(buffer_poll[0] != '\0'){
							fprintf(stdout,"[Proc %d : %s : stdout] %s \n",mod_y,machines[mod_y],buffer_poll);
							fflush(stdout);
						}
					}
					else{
						if(buffer_poll[0] != '\0')
							printf("[Proc %d : %s : stderr] %s \n",mod_y,machines[mod_y],buffer_poll);
					}

					while(buffer_poll[boucle_len] != '\0')
					{
						boucle_len++;
						buflen++;
					}
					for (raz=0;raz<buflen;raz++){
						buffer_poll[raz]='\0';
					}
				}
			}

			sleep(5);


		}


		for(i = 0; i < nombre_processus ; i++){

			/* on accepte les connexions des processus dsm */
			socklen_t tailleaddr = sizeof(distaddr[i]);
			do {
				sock_serv[i]=accept(sock_ecoute,(struct sockaddr* )&distaddr[i],&tailleaddr);
			}while((sock_serv[i]==-1)&&(errno==EINTR));
			if (sock_serv[i]==-1){
				perror( "accept" ); exit( EXIT_FAILURE );
			}
			/*  On recupere le nom de la machine distante */
			/* 1- d'abord la taille de la chaine */
			/* 2- puis la chaine elle-meme */
			printf("Read pour la machnine %d\n",i);
			do{
				readnames[i]=read(sock_serv[i],buffer_int,maxbuflen);//nom_machine_dis[i],maxbuflen);
			}while((readnames[i]==-1)&&(errno==EINTR));

			if (readnames[i]==-1){
				perror( "read" ); exit( EXIT_FAILURE );
			}
			printf("Nom de la machine %d est: %s\n",i,buffer_int);

			/* On recupere le pid du processus distant  */

			/* On recupere le numero de port de la socket */
			/* d'ecoute des processus distants */
		}

		/* envoi du nombre de processus aux processus dsm*/

		/* envoi des rangs aux processus dsm */

		/* envoi des infos de connexion aux processus */

		/* gestion des E/S : on recupere les caracteres */
		/* sur les tubes de redirection de stdout/stderr */
		/* while(1)
         {
            je recupere les infos sur les tubes de redirection
            jusqu'à ce qu'ils soient inactifs (ie fermes par les
            processus dsm ecrivains de l'autre cote ...)

         };
		 */

		/* on attend les processus fils */

		/* on ferme les descripteurs proprement */

		/* on ferme la socket d'ecoute */
		close(sock_ecoute);
	}
	exit(EXIT_SUCCESS);
}

